#include "MP3Parser.h"
#include <iostream>
#include <QApplication>

using namespace std;

// returns the data buffer size
unsigned char* MP3Parser::parse( SoundSample* parentSample, size_t & buffer_return_size)
{
	// stuff we need for the mpg123 decoder
	mpg123_handle *mpgHandle = NULL;
	size_t buffer_size = 0;
	size_t done = 0;
	int  ret  = MPG123_OK;
	
	// stream properties
	int  channels = 0, encoding = 0;
	long sampleRate = 0;
	
	// this buffer will hold all the data
	unsigned char* buffer = NULL;
	
	// initialize filestream
	mpg123_init();
	
	// create new file handle
	mpgHandle = mpg123_new(NULL, &ret);
	
	if(mpgHandle == NULL || (ret !=MPG123_OK))
	{
		cout << "Unable to create mpg123 handle: " << (mpg123_plain_strerror(ret)) << "\n";
		return NULL;
	}
	
	// open the filestream
	ret = mpg123_open( mpgHandle, (parentSample->getFilepath().toLatin1()));
	if (ret != MPG123_OK) 
	{
		cout << "Unable to open file " << (parentSample->getFilepath().toStdString());
		return NULL;
	}
	
	// read format information from the stream
	ret = mpg123_getformat(mpgHandle, &sampleRate, &channels, &encoding);
	
	if (ret != MPG123_OK) 
	{
		cout << "Unable to get format from file " << (parentSample->getFilepath().toStdString()) << "\n";
		return NULL;
	}
	
	// find out the sizes of samples to be decoded
	mpg123_scan(mpgHandle);
	
	// after calling scan, the length returned in the following
	// function is accurate and not just an estimated value
	buffer_size = mpg123_length(mpgHandle) * channels * 2;
	
	// to make the progess bar dialog work, 
	// we need to decode the mp3 piece by piece
	buffer = (unsigned char*) malloc (buffer_size);
	 
	unsigned char* buffer_ptr = buffer;
	
	for(int i = 0; i < 100; i++)
	{
		buffer_ptr = buffer + ( (buffer_size / 100)*i);
		
		ret = mpg123_read(mpgHandle, buffer_ptr, (buffer_size/100), &done);
		
		if (ret != MPG123_OK) {
			cout << "Error decoding " << (parentSample->getFilepath().toStdString()) << "\n";
			return NULL;
		}
		emit percentFinishedParsing(i+1);
		qApp->processEvents();
		
	}
		
	cout << done << " bytes of " << buffer_size << " total successfully decoded ";
	
	/* Done decoding, now just clean up and leave. */
	mpg123_close(mpgHandle);
	mpg123_delete(mpgHandle);
	mpg123_exit();

	buffer_return_size = buffer_size;
	
	return buffer;
}

int MP3Parser::gatherID3Info( SoundSample * parentSample)
{
	mpg123_handle* m;
	
	// variables holding the ID3 info
	mpg123_id3v1 *v1;
	mpg123_id3v2 *v2;
	
	int meta, channels, encoding, ret = MPG123_OK;
	long sampleRate;
	
	char tempString[10];
	
	mpg123_init();
	
	m = mpg123_new(NULL, &ret);
	
	if(m == NULL || (ret != MPG123_OK))
	{
		cout << "Unable to create mpg123 handle: " << (mpg123_plain_strerror(ret)) << "\n";
		return NULL;
	}
	
	ret = mpg123_open( m, parentSample->getFilepath().toLatin1());
	
	if ( ret != MPG123_OK)
	{
		cout << "Unable to open file " << (parentSample->getFilepath().toStdString()) << "\n";
		return NULL;
	}
	// read format information from the stream
	ret = mpg123_getformat(m, &sampleRate, &channels, &encoding);
	
	if (ret != MPG123_OK) 
	{
		cout << "Unable to get format from file " << (parentSample->getFilepath().toStdString()) << "\n";
		return NULL;
	}
	
	int mask;
	// set the samplerate of the parent sample
	// ------------------------------------------------------
	snprintf(tempString, 9 , "%li", sampleRate);
	parentSample->setSamplerate(QString(tempString));
	
	// set the channels of the parent sample
	// ------------------------------------------------------
	snprintf(tempString, 9 , "%i", channels);
	parentSample->setChannels(QString(tempString));
	
	// set the bitdepth of the parent sample
	// ------------------------------------------------------
	mask = MPG123_ENC_16;
	if( (encoding & MPG123_ENC_8) > 0 )
	{
		parentSample->setBitdepth(QString("8"));
	}
	else if ( (encoding & MPG123_ENC_16) > 0)
	{
		parentSample->setBitdepth(QString("16"));
	}
	else if ( (encoding & MPG123_ENC_24) > 0)
	{
		parentSample->setBitdepth(QString("24"));
	}
	else 
	{
		parentSample->setBitdepth(QString("nA"));
	}

	mpg123_scan(m);
	meta = mpg123_meta_check(m);
	
	if(meta & MPG123_ID3 && mpg123_id3(m, &v1, &v2) == MPG123_OK)
	{
		if(v1 != NULL) 
		{
			string buffer = v1->title;
			buffer.append(" , ");
			buffer.append(v1->comment);
			
			parentSample->setDescription(QString(buffer.c_str()));
		}
			
		
		if(v2 != NULL)
		{
			string buffer;
			
			MP3Parser::separateLines(buffer, v2->title);
			
			if(v2->comment != NULL && v2->comment->fill)
			{
				buffer.append(", ");
				MP3Parser::separateLines(buffer, v2->comment);
			}
			
			parentSample->setDescription(QString(buffer.c_str()));
		}
		
		mpg123_close(m);
	}
	
	mpg123_delete(m);
	mpg123_exit();
	return 0;
}

// internal methods used by gatherID3 Info
void MP3Parser::separateLines(string & buffer, mpg123_string* inlines)
{
	size_t i;
	int hadcr = 0, hadlf = 0;
	char *lines = NULL;
	char *line  = NULL;
	size_t len = 0;
	
	if(inlines != NULL && inlines->fill)
	{
		lines = inlines->p;
		len   = inlines->fill;
	}
	else return;
	
	line = lines;
	for(i=0; i<len; ++i)
	{
		if(lines[i] == '\n' || lines[i] == '\r' || lines[i] == 0)
		{
			// saving, changing, restoring a byte in the data
			char save = lines[i]; 
			
			if(save == '\n')
				++hadlf;
			if(save == '\r')
				++hadcr;
			if((hadcr || hadlf) && hadlf % 2 == 0 && hadcr % 2 == 0) 
				line = "";
			
			if(line)
			{
				lines[i] = 0;
				buffer.append(line);
				line = NULL;
				lines[i] = save;
			}
		}
		else
		{
			hadlf = hadcr = 0;
			if(line == NULL) 
			{
				line = lines+i;	
			}
		}
	}
}